from datetime import datetime

from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q
from django.http import Http404
from rest_framework import status
from rest_framework.authentication import SessionAuthentication
from rest_framework.decorators import api_view, permission_classes
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from exercise.models import Question, Blank, Choice, QuestionGroup
from exercise.pagination import ExerciseListPagination
from exercise.serializers import QuestionDetailSerializer, BlankSerializer, QuestionGroupDetailSerializer
from user.models import ProjUser, ProjUserGroup
from user.permissions import UserQuestionSelfEdit
from user.serializers import RegisterSerializer, ProjUserGroupListSerializer, ProjUserGroupDetailSerializer, \
    QuestionGroupUpdateSerializer
import json

# Create your views here.
@api_view(['POST'])
@permission_classes([AllowAny])
def user_register(request):
    """
    用于用户注册的api

    需要提交的json格式：

    ```json
    "data": {
        "username": "注册用户名",
        "password": "注册密码",
        "email": "注册邮箱"
    } // 可以只传送部分字段
    ```

    后端会校验上传的**用户名**以及**邮箱**的**唯一性**并返回校验结果
    """
    s = RegisterSerializer(data=request.data)
    if s.is_valid():
        s.save()
        return Response(data=s.data, status=status.HTTP_201_CREATED)
    return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)


class SelfUserInfo(APIView):
    permission_classes = [IsAuthenticated, ]

    def get_user(self, username):
        try:
            return ProjUser.objects.get(username=username)
        except ProjUser.DoesNotExist:
            raise Http404

    def get(self, request):
        """
        用户用于获取**自己**个人信息的api
        """
        user = self.get_user(request.user.username)
        s = RegisterSerializer(user)
        return Response(data=s.data, status=status.HTTP_200_OK)

    def put(self, request):
        """
        用户用于修改自己用户信息的api

        支持部分修改,上传数据格式:
        ```json
        "data": {
            "username": "新用户名",
            "password": "新密码",
            "email": "新邮箱"
        } // 可以只传送部分字段
        ```
        """
        user = self.get_user(request.user.username)
        s = RegisterSerializer(instance=user, data=request.data, partial=True)
        if s.is_valid():
            s.save()
            return Response(data=s.data, status=status.HTTP_200_OK)
        return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)


class UserGroupManage(APIView):
    permission_classes = [IsAuthenticated, ]
    pagination_class = ExerciseListPagination

    def get_user(self, username):
        try:
            return ProjUser.objects.get(username=username)
        except ProjUser.DoesNotExist:
            raise Http404

    def get_group(self, group_id):
        try:
            return ProjUserGroup.objects.get(id=group_id)
        except ProjUserGroup.DoesNotExist:
            raise Http404

    def get(self, request, group_id=None):  # 用户获取群组列表
        """
        用于获取数据库中全部群组简化描述的api

        可以在请求中指定查询关键字参数`q=xxx`来执行针对题目列表的模糊搜索

        该请求返回一个json数组：

        ```json
        [
            {
                "id": 1,
                "name": "小组",
                "creator": "admin"
            },
            //...  后面是结构相同的json对象
        ]
        ```
        """
        if group_id is not None:
            return Response({"message": "参数错误"})
        keyword = request.GET.get('q')
        if keyword:
            groups = ProjUserGroup.objects.filter(
                Q(id__icontains=keyword) |
                Q(name__icontains=keyword) |
                Q(description__icontains=keyword)
            )
        else:
            groups = ProjUserGroup.objects.all()

        paginator = self.pagination_class()
        paginated_groups = paginator.paginate_queryset(groups, request)
        s = ProjUserGroupListSerializer(paginated_groups, many=True)
        return paginator.get_paginated_response(s.data)

    def put(self, request, group_id):  # 用户加入群组
        """
        用于用户加入群组的api，只需要在url末尾指定希望加入的`group_id`即可
        """
        user = self.get_user(request.user.username)
        group = self.get_group(group_id)
        if not user.group_list.filter(id=group_id).exists():  # 用户不在该指定组里
            group.members.add(user)
            return Response({'message': '加入成功'}, status=status.HTTP_200_OK)
        else:
            return Response({'message': '您已经在组里'}, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, group_id):  # 用户退出群组
        """
        用于用户退出群组的api，只需要在url末尾指定希望退出的`group_id`即可
        """
        user = self.get_user(request.user.username)
        group = self.get_group(group_id)
        if user.group_list.filter(id=group_id).exists():  # 用户在指定组里
            group.members.remove(user)
            return Response({'message': '退出成功'}, status=status.HTTP_200_OK)
        else:
            return Response({'message': '您不在该群组内，无法django_admin_log退出'}, status=status.HTTP_400_BAD_REQUEST)


@api_view(['GET', ])
def get_group_detail(request, group_id):
    """
    通过在url最后指定`group_id`来唯一确定希望了解详情的群组
    """
    try:
        group = ProjUserGroup.objects.get(id=group_id)
    except ProjUserGroup.DoesNotExist:
        return Http404
    s = ProjUserGroupDetailSerializer(group)
    return Response(s.data, status=status.HTTP_200_OK)


class UserQuestionManage(APIView):
    permission_classes = [UserQuestionSelfEdit, ]
    authentication_classes = [SessionAuthentication, ]

    def get_user(self, username):
        try:
            return ProjUser.objects.get(username=username)
        except ProjUser.DoesNotExist:
            raise Http404

    def post(self, request, exercise_id=None):
        """
        支持上传两种题目，选择题和填空题，数据格式如下（除了注明选填的字段均为必填）：

        选择题：
        ```json
        "data": {
            "type":"CQ", // 这里意思是'Choice Question'
            "authority":0, // 题目的可见性，0为公开，1为不公开
            "stem": "这道题的题干",
            "name": "题目名称", // 选填，可以不提供该字段
            "label": "题目标签", // 10字符内
            "analysis": "题目解析",
            "choice": {
                "type": 0, // (0:单选题;1:多选题;2:不定项选择题)
                "options_cnt": 11, // 选项数
                "options": '{"A": "选项A", "B\": "选项B", "C": "选项C"}',
                "ans_cnt": 1, // 选项数
                "ans": "A" // 答案字符串，若为多选可以写为"ABC..."
            }
        }
        ```
        填空题：
        ```json
        "data": {
            "type":"FBQ", // 这里意思是'Fill in Blank Question'
            "authority":0, // 题目的可见性，0为公开，1为不公开
            "stem": "这道题的题干",
            "name": "题目名称", // 选填，可以不提供该字段
            "label": "题目标签", // 10字符内
            "analysis": "题目解析",
            "blank": {
                "blank_cnt": 2, // 题目的空数
                "ans": "{ // 依旧是json字符串
                    "1": [
                        "aa",
                        "bb"
                    ],
                    "2": [
                        "cc"
                    ]
                }"
            }
        }
        ```
        """
        s = QuestionDetailSerializer(data=request.data)
        if s.is_valid():
            s.validated_data['creator'] = request.user
            # s.validated_data['creator'] = ProjUser.objects.get(id=1)
            s.save()
            return Response(s.data, status=status.HTTP_201_CREATED)
        return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)

    def put(self, request, exercise_id):
        """
        在url末尾指定`exercise_id`来指定希望修改的题目

        向后端提交的json的`data`字段格式为对应`POST`方法数据提交格式的**子集**，即**支持部分更新**
        """
        try:
            question = Question.objects.get(id=exercise_id)
        except Question.DoesNotExist:
            return Response({'message': '题目编号不存在'}, status=status.HTTP_400_BAD_REQUEST)
        s = QuestionDetailSerializer(instance=question, data=request.data, partial=True)
        if s.is_valid():
            s.save()
            return Response(s.data, status=status.HTTP_200_OK)
        return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, exercise_id):
        """
        用于用户删除自己上传的题目的api，只需要在url末尾指定需要删除的题目id即可
        """
        try:
            question = Question.objects.get(id=exercise_id)
        except Question.DoesNotExist:
            return Response({'message': '题目编号不存在'}, status=status.HTTP_400_BAD_REQUEST)
        question.delete()
        return Response(status=status.HTTP_200_OK)


class UserQuestionGroupManage(APIView):
    permission_classes = [UserQuestionSelfEdit, ]
    # authentication_classes = [SessionAuthentication, ]

    def post(self, request):
        """
        向用户提供题组创建服务的api

        向后端提交数据的json格式约定如下:

        ```json
        "data": {
            "question_ids": [ // 创建题组时的原始题号
                5,
                1,
                4
            ],
            "user_groups": [ // 该题组被共享的群组号
                2,
                3
            ],
            "authority": 1, // 题组可见性(1:公开,0:私有)
            "name": "题组名称",
            "describe": "题组描述"
        }
        ```
        """
        s = QuestionGroupDetailSerializer(data=request.data)
        question_ids = s.initial_data.get('question_ids')
        # user_groups = s.initial_data.get('user_groups')
        if s.is_valid():
            s.validated_data['creator'] = request.user
            question_group = s.save()

            questions = Question.objects.filter(id__in=question_ids)
            question_group.questions.set(questions)

            return Response(s.data, status=status.HTTP_201_CREATED)
        return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)

    def put(self, request):
        """
        向用户提供更改自己创建题组信息的接口，支持部分更新

        向后端提交的json数据格式约定如下:

        ```json
        "data": {
            "add_question": [ // 向题组加入的题号，该字段可以为空（添加和删除不能互斥）
                5,
                1,
                4
            ],
            "del_question": [ // 从题组中删除的题号，该字段可以为空
                5,
                1,
                4
            ],
            "add_usergroups": [ // 向题组加入的共享群组，该字段可以为空（添加和删除不能互斥）
                2,
                3
            ],
            "del_usergroups": [ // 从题组中删除的共享群组，该字段可以为空
                2,
                3
            ],
            "authority": 1, // 题组可见性(0:公开,1:私有)
            "name": "新的题组名",
            "describe": "新的题组描述"
        }
        ```
        """
        id = request.data.get('id')
        print(id)
        try:
            question_group = QuestionGroup.objects.get(id=id)
        except QuestionGroup.DoesNotExist:
            return Response({'error': 'Question group does not exist.'}, status=status.HTTP_404_NOT_FOUND)
        
        # print("*****",question_group.creator.username, request.user)
        if question_group.creator != request.user:
            return Response({'error': 'You are not authorized to edit this question group.'},
                            status=status.HTTP_403_FORBIDDEN)

        serializer = QuestionGroupUpdateSerializer(instance=question_group, data=request.data, partial=True)
        if serializer.is_valid():

            add_question_ids = request.data.get('add_question', [])
            del_question_ids = request.data.get('del_question', [])
            if add_question_ids:
                questions = Question.objects.filter(id__in=add_question_ids)
                question_group.questions.add(*questions)
            elif del_question_ids:
                questions = Question.objects.filter(id__in=del_question_ids)
                question_group.questions.remove(*questions)

            add_usergroup_ids = request.data.get('add_usergroup', [])
            del_usergroup_ids = request.data.get('del_usergroup', [])
            if add_usergroup_ids:
                groups = ProjUserGroup.objects.filter(id__in=add_usergroup_ids)
                question_group.user_groups.add(*groups)
            elif del_usergroup_ids:
                groups = ProjUserGroup.objects.filter(id__in=del_usergroup_ids)
                question_group.user_groups.remove(*groups)
            print(add_usergroup_ids, del_usergroup_ids)

            serializer.save(create_time=datetime.now())
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['GET'])
def is_me_admin(request):
    """
    用于检测当前登录用户是否为管理员的api

    返回数据格式为:

    ```json
    "data": {
        "is_admin": True // 或者False
    }
    ```

    出现用户不存在的情况就会返回404
    """
    try:
        user = ProjUser.objects.get(username=request.user.username)
    except ProjUser.DoesNotExist:
        return Response({'message': "用户不存在"}, status=status.HTTP_404_NOT_FOUND)
    if user.is_admin:
        return Response({'is_admin': True})
    else:
        return Response({'is_admin': False})
